package dk.pervasivepositioning.project2;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.location.LocationManager;
import android.os.Environment;
import android.util.Log;

public class SmartDistancedBasedWithAcc extends SmartDistanceBasedStrategy
		implements SensorEventListener {

	private static final float alpha = 0.8f;
	private SensorManager mSensorManager;
	private long accTimestamp = 0;
	private float totalMeasure = 0;
	private List<Float> magnitudeMeasures = new ArrayList<Float>();
	private String sAccuracy;
	private long started;
	private float st;

	public SmartDistancedBasedWithAcc(String URL, LocationManager lm,
			int threshold, Activity activity, int maximumspeed)
			throws IOException {
		super(URL, lm, threshold, maximumspeed, activity);
		this.lm = lm;
		this.activity = activity;
		mSensorManager = (SensorManager) activity
				.getSystemService(Context.SENSOR_SERVICE);
		this.isMoving = false;
	}

	@Override
	public void startup() {
		Sensor mAccelerometer = mSensorManager
				.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
		mSensorManager.registerListener(this, mAccelerometer,
				SensorManager.SENSOR_DELAY_NORMAL);
		started = System.currentTimeMillis();
		startUpdates();
	}

	public void onAccuracyChanged(Sensor arg0, int accuracy) {
		String sAccuracy;

		switch (accuracy) {
		case SensorManager.SENSOR_STATUS_ACCURACY_HIGH:
			sAccuracy = " HIGH";
			break;
		case SensorManager.SENSOR_STATUS_ACCURACY_MEDIUM:
			sAccuracy = " MED";
			break;
		default:
			sAccuracy = " LOW";
			break;
		}

		this.sAccuracy = sAccuracy;
	}

	@Override
	public void shutdown() {
		mSensorManager.unregisterListener(this);
		super.stopUpdates();
	}

	public void onSensorChanged(SensorEvent event) {
		float magnitude = 0.0f;
		magnitude = (float) Math.sqrt(event.values[0] * event.values[0]
				+ event.values[1] * event.values[1] + event.values[2]
				* event.values[2]);
		magnitude = Math.abs(magnitude);
		// Too high peek discard it

		totalMeasure += magnitude;
		magnitudeMeasures.add(magnitude);

		if (accTimestamp == 0)
			accTimestamp = System.currentTimeMillis();
		else {

			if (accTimestamp + 1000 < System.currentTimeMillis()) {

				final float average = totalMeasure / magnitudeMeasures.size();
				float Q = 0;
				for (float magMeasure : magnitudeMeasures) {
					Q = Q + (magMeasure - average) * (magMeasure - average);
				}
				float variance = Q / (magnitudeMeasures.size());

				accTimestamp = System.currentTimeMillis();
				final float sd = (float) Math.sqrt(variance);

				if (st == 0) {
					st = sd;
				} else {
					st = alpha * sd + (1 - alpha) * st;
				}

				if (st >= 0.15f) {
					if (!isMoving) {
						isMoving = true;
					}
				} else {
					if (isMoving) {
						isMoving = false;
					}
				}
				printDebugInfo("filtered SD " + st + " ismoving: " + isMoving
						+ " accuracy: " + this.sAccuracy + "\n");

				magnitudeMeasures.clear();
				totalMeasure = 0;
			}
		}

	}

	@Override
	public String getStrategy() {
		return "smart-distanced-based-with-acc";
	}
}
